import pandas as pd
import numpy as np
import utm
from deap import base, creator, tools, algorithms
import random
import matplotlib.pyplot as plt

# 读取CSV文件并转换经纬度为UTM坐标
def read_and_convert_csv(file_path):
    df = pd.read_csv(file_path)
    coords = []
    for _, row in df.iterrows():
        lat, lon = row["纬度"], row["经度"]
        utm_coords = utm.from_latlon(lat, lon)
        coords.append((utm_coords[0], utm_coords[1]))
    return np.array(coords)

# 计算两点之间的欧几里得距离
def euclidean_distance(p1, p2):
    return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

# 计算总路径长度
def total_distance(path, coords):
    distance = 0.0
    for i in range(len(path)):
        distance += euclidean_distance(coords[path[i]], coords[path[(i + 1) % len(path)]])
    return distance

# 遗传算法设置
def genetic_algorithm(coords, population_size=500, generations=500, cxpb=0.5, mutpb=0.05):
    """
    参数：初始种群大小，迭代，交叉概率，变异概率
    """
    num_points = len(coords)

    creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
    creator.create("Individual", list, fitness=creator.FitnessMin)

    toolbox = base.Toolbox()
    toolbox.register("indices", random.sample, range(num_points), num_points)  #生成一个随机的节点序列
    toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.indices) #创建一个个体
    toolbox.register("population", tools.initRepeat, list, toolbox.individual) #创建一个种群

    # 计算个体路径的总距离
    def evalTSP(individual):
        return total_distance(individual, coords),

    toolbox.register("mate", tools.cxOrdered)
    toolbox.register("mutate", tools.mutShuffleIndexes, indpb=0.005)
    toolbox.register("select", tools.selTournament, tournsize=3)
    toolbox.register("evaluate", evalTSP)

    pop = toolbox.population(n=population_size)
    hof = tools.HallOfFame(1)
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("min", np.min)
    stats.register("avg", np.mean)

    algorithms.eaSimple(pop, toolbox, cxpb=cxpb, mutpb=mutpb, ngen=generations, 
                        stats=stats, halloffame=hof, verbose=True)

    return hof[0]

def plot_path(coordinates, path):
    plt.figure()
    for i in range(len(path)):
        start = coordinates[path[i]]
        end = coordinates[path[(i + 1) % len(path)]]
        plt.plot([start[0], end[0]], [start[1], end[1]], 'bo-')
    plt.xlabel('Longitude')
    plt.ylabel('Latitude')
    plt.show()

# 主程序
if __name__ == "__main__":
    file_path = "D:\Lenovo\Desktop\云南大学\空间数据挖掘\实验数据\data10_yn.csv"  # 替换为你的CSV文件路径
    print("Calculating...")
    coords = read_and_convert_csv(file_path)
    best_route = genetic_algorithm(coords)

    print("最短路径：")
    print(best_route)
    print("最短路径长度：")
    print(total_distance(best_route, coords))
    
    plot_path(coords, best_route)
